package by.apiskun.curex.dataaccess.impl;

import java.util.List;

import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.Validate;
import org.springframework.stereotype.Repository;

import by.apiskun.curex.dataaccess.UserDAO;
import by.apiskun.curex.datamodel.User;
import by.apiskun.curex.datamodel.User_;

@Repository
public class UserDAOImpl extends AbstractDAOImpl<Long, User> implements UserDAO {

	protected UserDAOImpl() {
		super(User.class);
	}

	@Override
	public Long getCount() {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

		CriteriaQuery<Long> criteria = cBuilder.createQuery(Long.class);
		Root<User> root = criteria.from(User.class);

		criteria.select(cBuilder.count(root));

		TypedQuery<Long> query = getEm().createQuery(criteria);
		return query.getSingleResult();
	}

	@Override
	public List<User> getAllUsers() {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

		CriteriaQuery<User> criteria = cBuilder.createQuery(User.class);
		Root<User> root = criteria.from(User.class);

		criteria.select(root);

		TypedQuery<User> query = getEm().createQuery(criteria);
		List<User> results = query.getResultList();
		return results;
	}

	@Override
	public List<User> getAllUsersByFirstName(String firstName) {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

		CriteriaQuery<User> root = cBuilder.createQuery(User.class);
		Root<User> criteria = root.from(User.class);

		root.select(criteria);
		root.where(cBuilder.equal(criteria.get(User_.userFirstName), firstName));

		TypedQuery<User> query = getEm().createQuery(root);
		List<User> results = query.getResultList();
		return results;
	}

	@Override
	public void updateUserPassword(Long id, String newPassword) {
		String q = String.format(
				"update from %s p set p.password=:newParam where p.id=:id",
				User.class.getSimpleName());
		Query updateQuery = getEm().createQuery(q);
		updateQuery.setParameter("newParam", newPassword);
		updateQuery.setParameter("id", id);
		int updatedRowsCount = updateQuery.executeUpdate();
		Validate.isTrue(updatedRowsCount == 1, "One row should be updated");
	}

	@Override
	public void updateUserPhoneNumber(Long id, String newPhoneNumber) {
		String q = String
				.format("update from %s p set p.userPhoneNumber=:newParam where p.id=:id",
						User.class.getSimpleName());
		Query updateQuery = getEm().createQuery(q);
		updateQuery.setParameter("newParam", newPhoneNumber);
		updateQuery.setParameter("id", id);
		int updatedRowsCount = updateQuery.executeUpdate();
		Validate.isTrue(updatedRowsCount == 1, "One row should be updated");
	}

	@Override
	public void updateUserLock(Long id, Boolean newUserLock) {
		String q = String.format(
				"update from %s p set p.userLock=:newParam where p.id=:id",
				User.class.getSimpleName());
		Query updateQuery = getEm().createQuery(q);
		updateQuery.setParameter("newParam", newUserLock);
		updateQuery.setParameter("id", id);
		int updatedRowsCount = updateQuery.executeUpdate();
		Validate.isTrue(updatedRowsCount == 1, "One row should be updated");

	}

	@Override
	public List<User> getAllUsersByLastName(String lastName) {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

		CriteriaQuery<User> root = cBuilder.createQuery(User.class);
		Root<User> criteria = root.from(User.class);

		root.select(criteria);
		root.where(cBuilder.equal(criteria.get(User_.userLastName), lastName));

		TypedQuery<User> query = getEm().createQuery(root);
		List<User> results = query.getResultList();
		return results;
	}

	@Override
	public List<User> getAllUsersByMidName(String midName) {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

		CriteriaQuery<User> root = cBuilder.createQuery(User.class);
		Root<User> criteria = root.from(User.class);

		root.select(criteria);
		root.where(cBuilder.equal(criteria.get(User_.userMidName), midName));

		TypedQuery<User> query = getEm().createQuery(root);
		List<User> results = query.getResultList();
		return results;
	}

	@Override
	public List<User> getAllUsersByFullName(String firstName, String midName,
			String lastName) {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

		CriteriaQuery<User> root = cBuilder.createQuery(User.class);
		Root<User> criteria = root.from(User.class);

		root.select(criteria);
		root.where(
				cBuilder.equal(criteria.get(User_.userFirstName), firstName),
				cBuilder.equal(criteria.get(User_.userMidName), midName),
				cBuilder.equal(criteria.get(User_.userLastName), lastName));

		TypedQuery<User> query = getEm().createQuery(root);
		List<User> results = query.getResultList();
		return results;
	}

	@Override
	public User getUserByLogin(String login) {
		CriteriaBuilder cBuilder = getEm().getCriteriaBuilder();

		CriteriaQuery<User> root = cBuilder.createQuery(User.class);
		Root<User> criteria = root.from(User.class);

		root.select(criteria);
		root.where(cBuilder.equal(criteria.get(User_.login), login));

		TypedQuery<User> query = getEm().createQuery(root);
		return query.getSingleResult();
	}

}
